﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;
using System.Windows;
using System.Windows.Media;
using System.Windows.Input;
using SHomeWorkshop.LunarTools;
using System.Windows.Media.Imaging;
using System.IO;

namespace SHomeWorkshop.LunarMind
{
    static class Globals
    {
        static Globals()
        {
            defFontFamily1 = new FontFamily("Simsun");
            defFontFamily2 = new FontFamily("Microsoft YaHei");

            if (pathOfMyDocuments.EndsWith("\\") == false)
            {
                pathOfMyDocuments += "\\";
            }

            pathOfUserDirectory = pathOfMyDocuments + "SHome WorkShop\\Lunar Mind\\";
            pathOfRecentlyFiles = pathOfUserDirectory + "RecentlyFiles.xml";
            pathOfStudentsList = pathOfUserDirectory + (Globals.pathOfUserDirectory.EndsWith("\\") ? "" : "\\") + "StudentsLists\\";

            if (installedPath.EndsWith("\\") == false)
            {
                installedPath += "\\";
            }

            tutorialPath = installedPath + "LWS-LunarMindTutorial.chm";

            fullPathOfApp = installedPath + appName + ".exe";

            pathOfInCommonUseImages = installedPath + "常用图像\\";

            //初始化根标题与SubRoot标题之间的线条色的列表。
            //lineBrushesList.Add(Brushes.Black);
            //lineBrushesList.Add(Brushes.Brown);
            //lineBrushesList.Add(Brushes.DarkMagenta);
            //lineBrushesList.Add(Brushes.DarkBlue);
            //lineBrushesList.Add(Brushes.DarkCyan);
            //lineBrushesList.Add(Brushes.DarkGreen);
            //lineBrushesList.Add(Brushes.DarkOrchid);
            //lineBrushesList.Add(Brushes.DarkSlateBlue);
            //lineBrushesList.Add(Brushes.DimGray);
            //lineBrushesList.Add(Brushes.Orange);

            // 这些色彩是试验过在白色背景下可用的，一般与白色文字搭配是可以看清文字的。
            // 关系线和一级标题的背景色通常应该保持一致。  2021年3月14日
            // var colorNames = @"黑色,橙色,绿色,青色,蓝色,紫色,蓝紫罗兰色,棕色,坚树色,军校蓝,查特酒绿,巧克力色,珊瑚色,矢车菊蓝,猩红,深蓝,深青,深金菊色,深灰,深绿,深卡其布色,深洋红,深橄榄绿,深橙色,深兰花紫,深红,鲑鱼色,深海绿,深石板蓝,深石板灰,深宝石绿,深紫罗兰色,深粉色,深天蓝,暗灰,道奇蓝,耐火砖色,森林绿,灯笼海棠色,金色,金菊黄,灰色,热粉色,印度红,靛青,草坪绿,浅蓝,浅珊瑚色,浅灰,浅绿,浅粉色,浅鲑鱼肉色,浅海绿,浅海蓝,浅石板灰,浅钢蓝,酸橙色,酸橙绿,洋红,栗色,中碧玉绿,中蓝,中兰花紫,中紫,中海绿,中石板蓝,中春绿,中宝石绿,中紫罗兰红,午夜蓝,海军蓝,橄榄色,橄榄褐,橙色,兰花紫,灰紫罗兰红,秘鲁色,粉红,李色,粉蓝,玫瑰棕色,皇室蓝,重褐色,鲑鱼肉色,沙棕色,海绿,黄土赭,银白,天蓝,石板蓝,石板灰,春绿,钢蓝,茶色,水鸭绿,蓟色,番茄色,宝石绿,紫罗兰色,黄绿";

            var colorNames = "White,Beige,Khaki,LightBlue,LightGray,Black,DarkGray,DarkSeaGreen,DarkOrange,Coral,CadetBlue";

            foreach (var bi in BrushManager.BrushesList)
            {
                //if(bi.Brush is ImageBrush)
                //{
                //    // 只应支持一个浅花纹背景，浅色——这个不支持添加到 List<Color> 中。
                //    continue;
                //}

                var bsh = bi.Brush as SolidColorBrush;
                if (bsh == null) continue;

                if (colorNames.Contains(bi.EnName)) continue;   // 这些是背景色，不应该成为分支线色。

                if (IsLightColor(bsh.Color))
                {
                    lightBrushesList.Add(bsh);
                }
                else
                {
                    darkBrushesList.Add(bsh);
                }
            }

            //设置文档边距时需要使用的转换器。
            thicknessConverter = new ThicknessConverter();

            //初始化下划线
            underLineTextDecoration = new TextDecoration(TextDecorationLocation.Underline,
                null, 2, TextDecorationUnit.Pixel, TextDecorationUnit.FontRecommended);
            //pen传入null才会跟随文字变色。

            thickConverter = new ThicknessConverter();

        }

        private static TextDecoration underLineTextDecoration;
        /// <summary>
        /// 标题备注块等使用的下划线。
        /// </summary>
        public static TextDecoration UnderLineTextDecoration
        {
            get { return underLineTextDecoration; }
        }

        /// <summary>
        ///应用程序名，一般用作消息框的标题或窗口标题。
        /// </summary>
        private static string appName = ((AssemblyTitleAttribute)Assembly.GetExecutingAssembly().GetCustomAttributes(typeof(AssemblyTitleAttribute), false)[0]).Title;

        public static string AppName
        {
            get { return appName; }
        }

        private static MainWindow mainWindow = null;

        private static ThicknessConverter thicknessConverter;
        /// <summary>
        /// 设置文档边距时需要使用的转换器。
        /// </summary>
        public static ThicknessConverter ThicknessConverter
        {
            get { return Globals.thicknessConverter; }
        }

        /// <summary>
        /// 是指向MainWindow的SelectedTitlesList属性的快捷方式。
        /// 本身无任何意义。只是为了便于敲击输入代码。
        /// </summary>
        public static List<Title> SelectedTitlesList
        {
            get
            {
                if (mainWindow == null) return null;
                return mainWindow.SelectedTitlesList;
            }
        }

        /// <summary>
        /// 主窗口。只允许赋值一次。
        /// </summary>
        public static MainWindow MainWindow
        {
            get { return Globals.mainWindow; }
            set
            {
                if (value == null)
                {
                    MessageBox.Show("不允许给Globals.MainWindow赋null值！", Globals.AppName,
                        MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }

                if (mainWindow == null)
                {
                    mainWindow = value;
                }
                else
                {
                    MessageBox.Show("不允许重复给Globals.MainWindow赋值！", Globals.AppName,
                        MessageBoxButton.OK, MessageBoxImage.Warning);
                    return;
                }
            }
        }

        public static string pathOfInCommonUseImages;

        /// <summary>
        /// 班级名册列表所在目录。
        /// </summary>
        public static string pathOfStudentsList;

        /// <summary>
        /// “我的文档”的实际路径
        /// </summary>
        public static string pathOfMyDocuments = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);

        /// <summary>
        /// 以"\"结尾。
        /// </summary>
        public static string pathOfUserDirectory;

        /// <summary>
        /// 指向一个Xml文档，此文档中保存了“最近打开的文件”列表。
        /// </summary>
        public static string pathOfRecentlyFiles;

        /// <summary>
        /// 取程序“运行目录”。
        /// </summary>
        public static string installedPath = System.AppDomain.CurrentDomain.BaseDirectory;

        public static string tutorialPath = "";

        /// <summary>
        /// 应用程序运行时全路径。
        /// </summary>
        public static string fullPathOfApp;

        public static PaperInfo defPaperInfo = PaperInfo.GetPaperInfo("A4");

        /// <summary>
        /// 命令行参数。只取第一个，不支持多文档。
        /// 只在程序启动时使用此参数。一旦用过，会立即将此参数值置为null。
        /// </summary>
        public static string cmdParameterString;

        /// <summary>
        /// 标题之间的空白区域（用来画自动关系线）的宽度。BetweenHigherAndLowerTitles
        /// </summary>
        private static readonly double blankAreaWidth = 30;

        public static double BlankAreaWidth
        {
            get
            {
                if (MainWindow != null)
                {
                    return MainWindow.DefaultFontSize * 2;
                }
                return blankAreaWidth;
            }
        }

        /// <summary>
        /// 这个也是标题之间的空白区域——不过只用在根标题与一级标题之间。
        /// </summary>
        private static readonly double blankAreaWidthMax = 60;

        public static double BlankAreaWidthMax
        {
            get
            {
                if (MainWindow != null)
                {
                    return MainWindow.DefaultFontSize * 2;
                }
                return blankAreaWidthMax;
            }
        }

        private static readonly double subRootTitleCtrlOffcet = 75;

        public static double SubRootTitleCtrlOffcet
        {
            get
            {
                if (MainWindow != null)
                {
                    return MainWindow.DefaultFontSize * 5;
                }
                return subRootTitleCtrlOffcet;
            }
        }

        /// <summary>
        /// 画面四边的留白。
        /// </summary>
        private static readonly double blankPaddingOfMainCanvas = 225;

        public static double BlankPaddingOfMainCanvas
        {
            get
            {
                if (MainWindow != null)
                {
                    return MainWindow.DefaultFontSize * 15;
                }
                return blankPaddingOfMainCanvas;
            }
        }

        private static readonly List<Brush> lightBrushesList = new List<Brush>();

        private static readonly List<Brush> darkBrushesList = new List<Brush>();

        /// <summary>
        /// 将RGB色彩转换为灰度，判断是否浅色。
        /// 当文档背景色为暗色时，应给出浅色系的默认文本色（白色）、浅色系的分支线色；
        /// 反之，当文档背景色为浅色系时，应给出暗色系的默认文本色（黑色）、暗色系的分支线色。
        /// 
        /// 此方法的转换理是将 RGB 色彩转换为灰度，然后判断。
        /// 本方法来自：https://bbs.csdn.net/topics/394555653
        /// </summary>
        /// <param name="color"></param>
        /// <returns></returns>
        public static bool IsLightColor(Color color)
        {
            double darkness = 1 - (0.299 * color.R + 0.587 * color.G + 0.114 * color.B) / 255;
            if (darkness < 0.5)
            {
                return true; // It's a light color
            }
            else
            {
                return false; // It's a dark color
            }
        }

        private static Random random = new Random();

        /// <summary>
        /// 从lineBrushesList随机取出一种色彩。
        /// </summary>
        public static Brush RandomBrush
        {
            get
            {
                int rIndex;
                var docBack = Globals.mainWindow.mainCanvas.Background;
                if (docBack is ImageBrush)
                {
                    // 只支持一种：浅花文背景色，应返回深色分支线色。
                    rIndex = random.Next(darkBrushesList.Count);
                    return darkBrushesList[rIndex];
                }

                var bsh = docBack as SolidColorBrush;
                if (bsh == null || IsLightColor(bsh.Color))
                {
                    // 文档背景默认视为浅色，应返回深色分支线色。
                    rIndex = random.Next(darkBrushesList.Count);
                    return darkBrushesList[rIndex];
                }

                // 文档背景为深色时，分支线色应为浅色。
                rIndex = random.Next(lightBrushesList.Count);
                return lightBrushesList[rIndex];
            }
        }

        /// <summary>
        /// 取出系统字体。
        /// </summary>
        public static string SysFontFamily { get; set; }

        private static readonly FontFamily defFontFamily1;
        private static readonly FontFamily defFontFamily2;

        /// <summary>
        /// 默认字体为宋体。二○一二年五月二十三日修改。
        /// </summary>
        public static FontFamily DefFontFamily
        {
            get
            {
                return Globals.defFontFamily2;
            }
        }

        /// <summary>
        /// 如果当前文件还未保存在磁盘，则返回 null。
        /// 如果当前文件存在，则返回与当前文件同名、同路径（但是无后缀名）的目录路径。
        /// 注意：不保证目录在磁盘上存在。
        /// </summary>
        public static string PathOfWorkspace
        {
            get
            {
                try
                {
                    var fi = new System.IO.FileInfo(Globals.MainWindow.FullPathOfDiskFile);
                    var dPath = fi.Directory.FullName;
                    if (dPath.EndsWith("\\") == false)
                        dPath += "\\";
                    return dPath + fi.Name.Substring(0, fi.Name.Length - fi.Extension.Length) + "\\";
                }
                catch
                {
                    return null;
                }
            }
        }

        public static string PathOfParentDirectory
        {
            get
            {
                try
                {
                    var fi = new System.IO.FileInfo(Globals.MainWindow.FullPathOfDiskFile);
                    var dPath = fi.Directory.FullName;
                    if (dPath.EndsWith("\\") == false)
                        dPath += "\\";
                    return dPath;
                }
                catch
                {
                    return null;
                }
            }
        }

        public static string GetChineseNumber(int num)
        {
            string numStr = num.ToString();
            numStr = numStr.Replace('0', '〇');
            numStr = numStr.Replace('1', '一');
            numStr = numStr.Replace('2', '二');
            numStr = numStr.Replace('3', '三');
            numStr = numStr.Replace('4', '四');
            numStr = numStr.Replace('5', '五');
            numStr = numStr.Replace('6', '六');
            numStr = numStr.Replace('7', '七');
            numStr = numStr.Replace('8', '八');
            numStr = numStr.Replace('9', '九');
            return numStr;
        }

        /// <summary>
        /// 终于解决了输入法的问题。
        /// 原先使用WinForm的输入法控制库终究不行——取不出当前输入法名称。
        /// </summary>
        /// <param name="enable">开、关。</param>
        public static void SwitchInputMethod(bool enable)
        {
            if (MainWindow == null) return;

            InputMethod.SetIsInputMethodEnabled(MainWindow, false);

            InputMethod.Current.ImeState = enable ? InputMethodState.On : InputMethodState.Off;
        }


        /// <summary>
        /// 载入图像文件。
        /// </summary>
        /// <param name="imageFilePath"></param>
        /// <returns></returns>
        public static BitmapImage LoadBitmapImageFromFile(string imageFilePath)
        {
            if (File.Exists(imageFilePath) == false) return null;
            try
            {
                using (BinaryReader reader = new BinaryReader(File.Open(imageFilePath, FileMode.Open)))
                {
                    FileInfo fi = new FileInfo(imageFilePath);
                    byte[] bytes = reader.ReadBytes((int)fi.Length);
                    reader.Close();

                    var bitmapImage = new BitmapImage();
                    bitmapImage.BeginInit();
                    bitmapImage.StreamSource = new MemoryStream(bytes);
                    bitmapImage.EndInit();
                    return bitmapImage;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, Globals.AppName, MessageBoxButton.OK, MessageBoxImage.Warning);
                return null;
            }
        }

        private static ThicknessConverter thickConverter;

        public static ThicknessConverter ThickConverter
        {
            get { return Globals.thickConverter; }
        }
    }
}
